/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.actions.zip;

import com.softwarecraftsmen.orogeny.buildLogs.BuildLog;
import static com.softwarecraftsmen.orogeny.buildLogs.Verbosity.AllDetails;
import org.jetbrains.annotations.NotNull;

import static java.lang.String.format;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import static java.util.Locale.UK;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class ZipEntryFilter
{
	private final BuildLog buildLog;

	public ZipEntryFilter(final @NotNull BuildLog buildLog)
	{
		this.buildLog = buildLog;
	}

	@NotNull
	public Set<ZipEntry> usefulZipEntries(final @NotNull ZipFile zipFile, final @NotNull Set<String> seenBeforeZipEntries)
	{
		return new LinkedHashSet<ZipEntry>()
		{{
			final Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
			while (enumeration.hasMoreElements())
			{
				final ZipEntry zipEntry = enumeration.nextElement();
				final String zipEntryName = zipEntry.getName();
				if (zipEntry.isDirectory())
				{
					writeIgnoringZipEntry(zipEntry, "it is a directory");
				}
				else if (startsWith(zipEntry, "META-INF/INDEX.LIST"))
				{
					writeIgnoringZipEntry(zipEntry, "it is an indexed jar list");
				}
				else if (startsWith(zipEntry, "META-INF/MANIFEST.MF"))
				{
					writeIgnoringZipEntry(zipEntry, "it is a manifest");
				}
				else if (startsWith(zipEntry, "META-INF") && (endsWith(zipEntry, ".RSA") || endsWith(zipEntry, ".DSA") || endsWith(zipEntry, ".PGP") || endsWith(zipEntry, ".SF")))
				{
					writeIgnoringZipEntry(zipEntry, "it is related to JAR signing");
				}
				else if (seenBeforeZipEntries.contains(zipEntryName))
				{
					writeIgnoringZipEntry(zipEntry, "it has been seen before");
				}
				else
				{
					seenBeforeZipEntries.add(zipEntryName);
					buildLog.writeMessage(AllDetails, format(UK, "Including %1$s", zipEntry));
					try
					{
						this.add(zipEntry);
					}
					catch(Throwable e)
					{
						throw new IllegalStateException(e);
					}
				}
			}
		}};
	}

	private boolean startsWith(final ZipEntry zipEntry, final String fileName) {return zipEntry.getName().startsWith(fileName);}

	private boolean endsWith(final ZipEntry zipEntry, final String fileName) {return zipEntry.getName().endsWith(fileName);}

	private void writeIgnoringZipEntry(final ZipEntry zipEntry, final String reason) {buildLog.writeMessage(AllDetails, format(UK, "Ignoring %1$s because %2$s.", zipEntry.getName(), reason));}
}
